#include <stx/test/test.hpp>

TEST_CASE (core_shell)
{
    auto shr   = ShellResult{};
    shr.status = 1;
    insert(shr.cout, "hello"s);
    insert(shr.cout, "world"s);
    insert(shr.cerr, "123"s);
    insert(shr.cerr, "789"s);
    CHECK("STATUS:1|STDOUT:hello|world|STDERR:123|789"sv == tos(shr));

    auto ssr   = ShellRawResult{};
    ssr.status = 1;
    insert(ssr.cout, Buffer{std::byte(0xab), std::byte(0xcd)});
    insert(ssr.cout, Buffer{std::byte(0x12), std::byte(0x34)});
    insert(ssr.cerr, Buffer{std::byte(0xa0), std::byte(0xb1)});
    insert(ssr.cerr, Buffer{std::byte(0x56), std::byte(0x78)});
    CHECK("STATUS:1|STDOUT:abcd|1234|STDERR:a0b1|5678"sv == tos(ssr));

    LOOP_N (5)
    {
        auto status = shell(
                          "grep ll"_sv,
                          [](bool const is_cout, Buffer& buf) -> Future<Status>
                          {
                              if (!is_cout || buf.empty())
                              {
                                  xerr("Invalid output: "sv, buf.tosv());
                              }

                              co_return 0;
                          },
                          5s,
                          [](FileDescriptor fd) -> Future<Status>
                          {
                              write(fd.fd(), "hello"sv).get();
                              co_return 0;
                          })
                          .get();
        CHECK(C_STATUS_SUCCESS == status, status);
    }

    auto status = shell(
                      "ls /"_sv,
                      [](bool const is_cout, Buffer& buf) -> Future<Status>
                      {
                          if (!is_cout || buf.empty())
                          {
                              xerr("Invalid output: "sv, buf.size());
                          }

                          co_return 0;
                      },
                      5s)
                      .get();
    CHECK(C_STATUS_SUCCESS == status);

    status = shell(
                 "grep ll"_sv,
                 [](bool const is_cout, Buffer& buf) -> Future<Status>
                 {
                     if (!is_cout || buf.empty())
                     {
                         xerr("Invalid output: "sv, buf.size());
                     }

                     co_return 0;
                 },
                 5s,
                 [](FileDescriptor fd) -> Future<Status>
                 {
                     co_await write(fd.fd(), "hello"sv);
                     co_return 0;
                 })
                 .get();
    CHECK(C_STATUS_SUCCESS == status);

    status = shell("ls /"_sv,
                   [](bool const is_cout, Buffer& buf) -> Future<Status>
                   {
                       if (!is_cout || buf.empty())
                       {
                           xerr("Invalid output: "sv, buf.size());
                       }

                       co_return 0;
                   })
                 .get();
    CHECK(C_STATUS_SUCCESS == status);

    status = shell(
                 "grep ll"_sv,
                 [](bool const is_cout, std::string str) -> Future<Status>
                 {
                     if (!is_cout || str.empty())
                     {
                         xerr("Invalid output: "sv, str.size());
                     }

                     co_return 0;
                 },
                 5s,
                 [](FileDescriptor fd) -> Future<Status>
                 {
                     co_await write(fd.fd(), "hello"sv);
                     co_return 0;
                 })
                 .get();
    CHECK(C_STATUS_SUCCESS == status);

    status = shell(
                 "ls /"_sv,
                 [](bool const is_cout, std::string str) -> Future<Status>
                 {
                     if (!is_cout || str.empty())
                     {
                         xerr("Invalid output: "sv, str.size());
                     }

                     co_return 0;
                 },
                 5s)
                 .get();
    CHECK(C_STATUS_SUCCESS == status);

    status = shell(
                 "grep ll"_sv,
                 [](bool const is_cout, std::string str) -> Future<Status>
                 {
                     if (!is_cout || str.empty())
                     {
                         xerr("Invalid output: "sv, str.size());
                     }

                     co_return 0;
                 },
                 [](FileDescriptor fd) -> Future<Status>
                 {
                     co_await write(fd.fd(), "hello"sv);
                     co_return 0;
                 })
                 .get();
    CHECK(C_STATUS_SUCCESS == status);

    status = shell("ls /"_sv,
                   [](bool const is_cout, std::string str) -> Future<Status>
                   {
                       if (!is_cout || str.empty())
                       {
                           xerr("Invalid output: "sv, str.size());
                       }

                       co_return 0;
                   })
                 .get();
    CHECK(C_STATUS_SUCCESS == status);

    shr = shell("grep ll"_sv, 5s, "hello"sv).get();
    CHECK(C_STATUS_SUCCESS == shr.status);
    CHECK(1 == shr.cout.size());
    CHECK(shr.cerr.empty());
    CHECK("hello"sv == shr.cout.front());

    shr = shell("grep ll"_sv, "hello"sv).get();
    CHECK(C_STATUS_SUCCESS == shr.status);
    CHECK(1 == shr.cout.size());
    CHECK(shr.cerr.empty());
    CHECK("hello"sv == shr.cout.front());

    shr = shell("ls /"_sv, 5s).get();
    CHECK(C_STATUS_SUCCESS == shr.status);
    CHECK(shr.cout.size() >= 1);
    CHECK(shr.cerr.empty());

    shr = shell("ls /"_sv).get();
    CHECK(C_STATUS_SUCCESS == shr.status);
    CHECK(shr.cout.size() >= 1);
    CHECK(shr.cerr.empty());

    ssr = shellRaw("grep ll"_sv, 5s, "hello"sv).get();
    CHECK(C_STATUS_SUCCESS == ssr.status);
    CHECK(1 == ssr.cout.size());
    CHECK(ssr.cerr.empty());
    CHECK(MemView("hello\n"sv) == MemView(ssr.cout.front()));

    ssr = shellRaw("grep ll"_sv, "hello"sv).get();
    CHECK(C_STATUS_SUCCESS == ssr.status);
    CHECK(1 == ssr.cout.size());
    CHECK(ssr.cerr.empty());
    CHECK(MemView("hello\n"sv) == MemView(ssr.cout.front()));

    ssr = shellRaw("ls /"_sv, 5s).get();
    CHECK(C_STATUS_SUCCESS == ssr.status);
    CHECK(ssr.cout.size() >= 1);
    CHECK(ssr.cerr.empty());

    ssr = shellRaw("ls /"_sv).get();
    CHECK(C_STATUS_SUCCESS == ssr.status);
    CHECK(ssr.cout.size() >= 1);
    CHECK(ssr.cerr.empty());
}